package com.example.java_gobang.model;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.game.AIUser;
import com.example.java_gobang.game.OnlineUserManager;
import com.example.java_gobang.game.RoomManager;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

@Slf4j
@Data
public class Room {
    private String roomId;
    private User user1;
    private User user2;
    private int whiteUserId;

    private OnlineUserManager onlineUserManager;
    private RoomManager roomManager;
    private UserMapper userMapper;

    private ObjectMapper objectMapper = new ObjectMapper();

    public Room() {
        //使用UUID生成一串字符串给roomId赋值
        roomId = UUID.randomUUID().toString();
        //通过入口类中记录的 context 来手动获取到前面的 RoomManager 和 OnlineUserManager
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }

    //无棋子为0， 玩家1下子为1， 玩家2下子为2
    int[][] chessBoard = new int[15][15];

    public void putChess(GameRequest gameRequest) throws IOException {
        int chess = gameRequest.getUserId() == user1.getUserId() ? 1 : 2;
        int row = gameRequest.getRow();
        int col = gameRequest.getCol();
        if (chessBoard[row][col] != 0) {
            log.info("当前位置" + row + "," + col + "已经有子了！");
            return;
        }
        chessBoard[row][col] = chess;

        boolean isBot = false;
        if (user2.getUserId() == -1) {
            isBot = true;
        }
        //TODO 胜负判定
        int winner = checkWinner(row, col, chess);

        GameResponse gameResponse = new GameResponse();
        gameResponse.setMessage("putChess");
        gameResponse.setUserId(gameRequest.getUserId());
        gameResponse.setRow(row);
        gameResponse.setCol(col);
        gameResponse.setWinner(winner);

        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = null;
        if (!isBot) {
            session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        }
        if (session1 == null) {
            gameResponse.setWinner(user2.getUserId());
            log.info("玩家1 掉线！");
        }

        if (!isBot && session2 == null) {
            gameResponse.setWinner(user1.getUserId());
            log.info("玩家2 掉线！");
        }
        String respJson = objectMapper.writeValueAsString(gameResponse);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(respJson));
        }
        if (!isBot && session2 != null) {
            session2.sendMessage(new TextMessage(respJson));
        }

        if (gameResponse.getWinner() != 0) {
            log.info("游戏结束，房间销毁roomId = " + roomId + "获胜方为：" + gameResponse.getWinner());
            int winUserId = gameResponse.getWinner();
            int loseUserId = winUserId == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            //更新数据库信息
            userMapper.userWin(winUserId);
            if (!isBot) {
                userMapper.userLose(loseUserId);
            }
            //销毁房间
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

    private int checkWinner(int row, int col, int chess) {
        // 1. 检查所有的行
        //    先遍历这五种情况
        for (int c = col - 4; c <= col; c++) {
            // 针对其中的一种情况, 来判定这五个子是不是连在一起了~
            // 不光是这五个子得连着, 而且还得和玩家落的子是一样~~ (才算是获胜)
            try {
                if (chessBoard[row][c] == chess
                        && chessBoard[row][c + 1] == chess
                        && chessBoard[row][c + 2] == chess
                        && chessBoard[row][c + 3] == chess
                        && chessBoard[row][c + 4] == chess) {
                    // 构成了五子连珠! 胜负已分!
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                // 如果出现数组下标越界的情况, 就在这里直接忽略这个异常.
                continue;
            }
        }

        // 2. 检查所有列
        for (int r = row - 4; r <= row; r++) {
            try {
                if (chessBoard[r][col] == chess
                        && chessBoard[r + 1][col] == chess
                        && chessBoard[r + 2][col] == chess
                        && chessBoard[r + 3][col] == chess
                        && chessBoard[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (chessBoard[r][c] == chess
                        && chessBoard[r + 1][c + 1] == chess
                        && chessBoard[r + 2][c + 2] == chess
                        && chessBoard[r + 3][c + 3] == chess
                        && chessBoard[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (chessBoard[r][c] == chess
                        && chessBoard[r + 1][c - 1] == chess
                        && chessBoard[r + 2][c - 2] == chess
                        && chessBoard[r + 3][c - 3] == chess
                        && chessBoard[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        // 胜负未分, 就直接返回 0 了.
        return 0;
    }

    public void AImove() {
        log.info("AImove");
        AIUser aiUser = new AIUser(chessBoard);
        int[] move = aiUser.getNextMove();
        int moveRow = move[0];
        int moveCol = move[1];
        GameRequest gameRequest = new GameRequest();
        gameRequest.setMessage("putChess");
        gameRequest.setUserId(-1);
        gameRequest.setRow(moveRow);
        gameRequest.setCol(moveCol);
        log.info("AImove:{},{}", moveRow, moveCol);
        try {
            putChess(gameRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
